﻿using Application.Commons.Data;
using AutoMapper;
using Domain.Entities.Modulers;
using FrameworkCore.Constants;
using FrameworkCore.Extensions;
using FrameworkCore.Helpers;
using FrameworkCore.Models;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using NM.Module.Manager.API.EventHandlers;
using System.ComponentModel.DataAnnotations;

namespace NM.Module.Manager.API.Commands.Install;

#nullable disable

/// <summary>
/// 模块安装
/// </summary>
public class InstallModulerCommand : IRequest<Result<bool>>
{
    /// <summary>
    /// 模块库主键
    /// </summary>
    [Required(ErrorMessage = "模块库主键必传")]
    public long ModulerLibraryId { get; set; }

    /// <summary>
    /// 安装成功后是否重启，默认不重启
    /// </summary>
    public bool RestartAfterInstall { get; set; } = false;
}

/// <summary>
/// 处理程序
/// </summary>
public class InstallModulerCommandHandler : IRequestHandler<InstallModulerCommand, Result<bool>>
{
    private readonly ApplicationDbContext _context;

    public InstallModulerCommandHandler(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<Result<bool>> Handle(InstallModulerCommand request, CancellationToken cancellationToken)
    {
        var modulerLibrary = await _context.ModulerLibraries.FindAsync(request.ModulerLibraryId);
        ExceptionHelper.ThrowIfNull(modulerLibrary, "模块不存在");

        var uploadPath = ApplicationPartManagerExtensions
            .GetModulesDirectory(ConfigurationsExtensions.GetGlobalSection<List<string>>(GlobalConstants.UploadPathsKey));

        string sourcePath = Path.Combine(uploadPath, modulerLibrary.Name);
        string destinationPath = Path.Combine(ApplicationPartManagerExtensions
            .GetModulesDirectory(ConfigurationsExtensions.GetGlobalSection<List<string>>(GlobalConstants.ModulePathsKey)),
            GlobalConstants.PackagesFolderName);

        if (!Directory.Exists(destinationPath))
        {
            Directory.CreateDirectory(destinationPath);
        }

        destinationPath = Path.Combine(destinationPath, modulerLibrary.Name);
        File.Copy(sourcePath, destinationPath, true);

        var moduler = await _context.Modulers.SingleOrDefaultAsync(x => x.Name == modulerLibrary.Name);
        if (moduler == null)
        {
            moduler = new Moduler() 
            { 
                Title = modulerLibrary.Title, 
                Name = modulerLibrary.Name, 
                Version = modulerLibrary.Version, 
                ModulerLibraryId = modulerLibrary.Id 
            };
            moduler.AddDomainEvent(new InstallEvent(request.RestartAfterInstall));
            await _context.Modulers.AddAsync(moduler);
        }
        else
        {
            moduler.Title = modulerLibrary.Title;
            moduler.Name = modulerLibrary.Name;
            moduler.Version = modulerLibrary.Version;
            moduler.ModulerLibraryId = modulerLibrary.Id;
            moduler.AddDomainEvent(new InstallEvent(request.RestartAfterInstall));
            _context.Modulers.Update(moduler);
        }

        var count = await _context.SaveChangesAsync(cancellationToken);
        if (count == 0)
        {
            File.Delete(destinationPath);
        }
        ExceptionHelper.ThrowIfTrue(count == 0, "安装失败");

        return await Result<bool>.SucceedAsync(true);
    }
}